#include "Avalon/IOTests/DelimitedReaderTester.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/BufferReader.hpp"
#include "Avalon/IO/DelimitedReader.hpp"

using namespace Avalon;
using namespace Avalon::IO;
using namespace Avalon::IO::Tests;
using namespace boost;
using namespace boost::posix_time;
using namespace std;

void DelimitedReaderTester::TestEmpty() {
  BufferReader bufferReader("");
  DelimitedReader delimitedReader(bufferReader, '^');
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}

void DelimitedReaderTester::TestWithoutDelimiter() {
  string message = "hello world";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  CPPUNIT_ASSERT(!delimitedReader.IsAtEndOfDataSource());
  Buffer data;
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) ==
    message.size());
  CPPUNIT_ASSERT(data.GetSize() == message.size());
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(), message.size()) == 0);
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}

void DelimitedReaderTester::TestSingleDelimiter() {
  string message = "hello world^";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  CPPUNIT_ASSERT(!delimitedReader.IsAtEndOfDataSource());
  Buffer data;
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) ==
    message.size() - 1);
  CPPUNIT_ASSERT(data.GetSize() == message.size() - 1);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(),
    message.size() - 1) == 0);
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}

void DelimitedReaderTester::TestTwoDelimiters() {
  string message = "hello world^goodbye sky^";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  CPPUNIT_ASSERT(!delimitedReader.IsAtEndOfDataSource());
  Buffer data;
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(), 11) == 0);
  data.Reset();
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "goodbye sky", 11) == 0);
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}

void DelimitedReaderTester::TestWithAndWithoutDelimiters() {
  string message = "hello world^goodbye sky";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  CPPUNIT_ASSERT(!delimitedReader.IsAtEndOfDataSource());
  Buffer data;
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(), 11) == 0);
  data.Reset();
  CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "goodbye sky", 11) == 0);
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}

void DelimitedReaderTester::TestManyDelimiters() {
  const int LETTER_COUNT = 7;
  string message = "a^b^c^d^e^f^g";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  char nextLetter = 'a';
  for(int i = 0; i < LETTER_COUNT; ++i) {
    Buffer data;
    CPPUNIT_ASSERT(delimitedReader.Read(&data)->Get(seconds(1)) == 1);
    CPPUNIT_ASSERT(data.GetSize() == 1);
    CPPUNIT_ASSERT(strncmp(data.GetData(), &nextLetter, 1) == 0);
    if(i < LETTER_COUNT - 1) {
      CPPUNIT_ASSERT(!delimitedReader.IsAtEndOfDataSource());
    } else {
      CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
    }
    ++nextLetter;
  }
}

void DelimitedReaderTester::TestReadSome() {
  string message = "hello^world";
  BufferReader bufferReader(message);
  DelimitedReader delimitedReader(bufferReader, '^');
  Buffer data;
  CPPUNIT_ASSERT(delimitedReader.Read(&data, 3)->Get(seconds(1)) == 3);
  CPPUNIT_ASSERT(data.GetSize() == 3);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "hel", 3) == 0);
  data.Reset();
  CPPUNIT_ASSERT(delimitedReader.Read(&data, 100)->Get(seconds(1)) == 2);
  CPPUNIT_ASSERT(data.GetSize() == 2);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "lo", 2) == 0);
  data.Reset();
  CPPUNIT_ASSERT(delimitedReader.Read(&data, 3)->Get(seconds(1)) == 3);
  CPPUNIT_ASSERT(data.GetSize() == 3);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "wor", 3) == 0);
  data.Reset();
  CPPUNIT_ASSERT(delimitedReader.Read(&data, 100)->Get(seconds(1)) == 2);
  CPPUNIT_ASSERT(data.GetSize() == 2);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "ld", 2) == 0);
  CPPUNIT_ASSERT(delimitedReader.IsAtEndOfDataSource());
}
